package cn.turboinfo.fuyang.api.domain.scheduler.usecase.stat;

import cn.turboinfo.fuyang.api.domain.common.service.kvconfig.KVConfigService;
import cn.turboinfo.fuyang.api.domain.common.service.order.ServiceOrderService;
import cn.turboinfo.fuyang.api.domain.common.service.stat.OrderStatService;
import cn.turboinfo.fuyang.api.domain.common.usecase.AbstractUseCase;
import cn.turboinfo.fuyang.api.entity.common.enumeration.order.ServiceOrderStatus;
import cn.turboinfo.fuyang.api.entity.common.pojo.kvconfig.KVConfig;
import cn.turboinfo.fuyang.api.entity.common.pojo.kvconfig.KVConfigCreator;
import cn.turboinfo.fuyang.api.entity.common.pojo.kvconfig.KVConfigUpdater;
import cn.turboinfo.fuyang.api.entity.common.pojo.order.QServiceOrder;
import cn.turboinfo.fuyang.api.entity.common.pojo.order.ServiceOrder;
import cn.turboinfo.fuyang.api.entity.common.pojo.stat.OrderStatCreator;
import cn.turboinfo.fuyang.api.entity.common.pojo.stat.OrderStatUpdater;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.helper.component.request.QPageRequestHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 订单统计
 *
 * @author hai
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SchedulerStatOrderUseCase extends AbstractUseCase<SchedulerStatOrderUseCase.InputData, SchedulerStatOrderUseCase.OutputData> {

    private final ServiceOrderService serviceOrderService;

    private final OrderStatService orderStatService;

    private final KVConfigService kvConfigService;

    static String ORDER_STAT_LATEST_DATA = "ORDER_STAT_LATEST_DATA";

    @Override
    protected OutputData doAction(InputData inputData) {

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime;
        LocalDateTime endTime = now.minusDays(1).with(LocalTime.MAX);

        // 1. 查询最后统计时间
        KVConfig kvConfig = kvConfigService.getByConfigKey(ORDER_STAT_LATEST_DATA).orElse(null);

        // 2. 查询最后统计时间之后的订单
        if (kvConfig == null) {
            startTime = LocalDateTime.of(2023, 1, 1, 0, 0, 0);
        } else {
            String configValue = kvConfig.getConfigValue();
            startTime = LocalDateTime.parse(configValue);
            // 如果最后统计时间大于开始统计时间，则不统计
            if (startTime.isAfter(endTime)) {
                return OutputData.builder()
                        .build();
            }
        }

        val request = QRequest.newInstance();
        request.filterIn(QServiceOrder.orderStatus, Arrays.asList(new ServiceOrderStatus[]{ServiceOrderStatus.SERVICE_COMPLETED, ServiceOrderStatus.COMPLETED}));
        request.filterBetween(QServiceOrder.completedTime, startTime, endTime);
        val requestPage = QPage.newInstance()
                .paging(0, 100);
        Map<String, List<ServiceOrder>> orderMap = QPageRequestHelper.request(request, requestPage, serviceOrderService::findAll)
                .stream()
                .collect(Collectors.groupingBy(order -> StringUtils.join(new String[]{order.getCompanyId().toString(), order.getCategoryId().toString(), String.valueOf(order.getCompletedTime().getYear()), String.valueOf(order.getCompletedTime().getMonthValue())}, "-")));

        for (Map.Entry<String, List<ServiceOrder>> entry : orderMap.entrySet()) {
            String[] key = entry.getKey().split("-");
            Long companyId = Long.valueOf(key[0]);
            Long categoryId = Long.valueOf(key[1]);
            int year = Integer.parseInt(key[2]);
            int month = Integer.parseInt(key[3]);
            Long count = (long) entry.getValue().size();

            orderStatService.getByCompanyIdAndCategory(companyId, categoryId, year, month)
                    .ifPresentOrElse(
                            orderStat -> {
                                OrderStatUpdater creator = OrderStatUpdater
                                        .builder(orderStat.getId())
                                        .withOrderCount(count)
                                        .build();
                                orderStatService.update(creator);
                            },
                            () -> {
                                OrderStatCreator creator = OrderStatCreator
                                        .builder()
                                        .withCompanyId(companyId)
                                        .withCategoryId(categoryId)
                                        .withYear(year)
                                        .withMonth(month)
                                        .withOrderCount(count)
                                        .build();
                                orderStatService.save(creator);
                            }
                    );
            // 保存 kvConfig
            if (kvConfig == null) {
                KVConfigCreator kvConfigCreator = KVConfigCreator
                        .builder()
                        .withConfigKey(ORDER_STAT_LATEST_DATA)
                        .withConfigValue(LocalDate.of(year, month, 1).atStartOfDay().toString())
                        .build();
                kvConfigService.save(kvConfigCreator);
            } else {
                KVConfigUpdater kvConfigUpdater = KVConfigUpdater
                        .builder(kvConfig.getId())
                        .withConfigValue(LocalDate.of(year, month, 1).atStartOfDay().toString())
                        .build();
                kvConfigService.update(kvConfigUpdater);
            }
        }

        return OutputData.builder()
                .build();
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    public static class InputData extends AbstractUseCase.InputData {

    }

    @Getter
    @Setter
    @Builder
    public static class OutputData extends AbstractUseCase.OutputData {

    }
}
